/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using DaveSexton.DocProject.Engine;
using System.ComponentModel;

namespace DaveSexton.DocProject
{
	public enum UpdatedBuildTypeDependency
	{
		/// <summary>
		/// A build does not have to occur because of an updated item.
		/// </summary>
		None,
		/// <summary>
		/// A partial build should occur when the item has been updated.
		/// </summary>
		Partial,
		/// <summary>
		/// A full build should occur when the item has been updated.
		/// </summary>
		Full
	}

	public enum MissingBuildTypeDependency
	{
		/// <summary>
		/// A build does not have to occur because of a missing item.
		/// </summary>
		None,
		/// <summary>
		/// A partial build will replace the missing item.  It's assumed that a full build will replace the item as well.
		/// </summary>
		Partial,
		/// <summary>
		/// Only a full build will replace the missing item.
		/// </summary>
		Full,
		/// <summary>
		/// A full build depends on the item, but will not replace it, so the build should fail.
		/// </summary>
		Error
	}

	public abstract class DocProjectItemBase
	{
		#region Public Properties
		public bool RemoveOnClean
		{
			get
			{
				return removeOnClean;
			}
		}

		public bool IncludeInProject
		{
			get
			{
				return includeInProject;
			}
		}

		public bool IsRequiredOutput
		{
			get
			{
				return isRequiredOutput;
			}
		}

		public MissingBuildTypeDependency MissingBuildTypeDependency
		{
			get
			{
				return missingBuildTypeDependency;
			}
			set
			{
				if (!Enum.IsDefined(typeof(MissingBuildTypeDependency), value))
					throw new InvalidEnumArgumentException("value", (int) value, typeof(MissingBuildTypeDependency));

				missingBuildTypeDependency = value;
			}
		}

		public UpdatedBuildTypeDependency UpdatedBuildTypeDependency
		{
			get
			{
				return updatedBuildTypeDependency;
			}
			set
			{
				if (!Enum.IsDefined(typeof(UpdatedBuildTypeDependency), value))
					throw new InvalidEnumArgumentException("value", (int) value, typeof(UpdatedBuildTypeDependency));

				updatedBuildTypeDependency = value;
			}
		}

		public abstract bool Exists { get; }

		public virtual bool AnyExists
		{
			get
			{
				return Exists;
			}
		}

		public abstract SystemPath Path { get; }
		#endregion

		#region Private / Protected
		private readonly bool removeOnClean, includeInProject, isRequiredOutput;
		private MissingBuildTypeDependency missingBuildTypeDependency;
		private UpdatedBuildTypeDependency updatedBuildTypeDependency;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="DocProjectItemBase" /> class for derived types.
		/// </summary>
		protected DocProjectItemBase(bool removeOnClean, bool includeInProject)
		{
			this.removeOnClean = removeOnClean;
			this.includeInProject = includeInProject;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="DocProjectItemBase" /> class for derived types.
		/// </summary>
		protected DocProjectItemBase(bool removeOnClean, bool includeInProject, bool isRequiredOutput)
			: this(removeOnClean, includeInProject)
		{
			this.isRequiredOutput = isRequiredOutput;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="DocProjectItemBase" /> class for derived types.
		/// </summary>
		/// <param name="missingBuildTypeDependency">Indicates the <see cref="BuildType" /> that can be executed to replace the item when the item is missing.</param>
		/// <param name="updatedBuildTypeDependency">Indicates the <see cref="BuildType" /> that is executed when the item has changed.</param>
		protected DocProjectItemBase(bool removeOnClean, bool includeInProject, MissingBuildTypeDependency missingBuildTypeDependency, UpdatedBuildTypeDependency updatedBuildTypeDependency)
		{
			if (!Enum.IsDefined(typeof(MissingBuildTypeDependency), missingBuildTypeDependency))
				throw new InvalidEnumArgumentException("missingBuildTypeDependency", (int) missingBuildTypeDependency, typeof(MissingBuildTypeDependency));

			if (!Enum.IsDefined(typeof(UpdatedBuildTypeDependency), updatedBuildTypeDependency))
				throw new InvalidEnumArgumentException("updatedBuildTypeDependency", (int) updatedBuildTypeDependency, typeof(UpdatedBuildTypeDependency));

			this.removeOnClean = removeOnClean;
			this.includeInProject = includeInProject;
			this.missingBuildTypeDependency = missingBuildTypeDependency;
			this.updatedBuildTypeDependency = updatedBuildTypeDependency;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="DocProjectItemBase" /> class for derived types.
		/// </summary>
		/// <param name="missingBuildTypeDependency">Indicates the <see cref="BuildType" /> that can be executed to replace the item when the item is missing.</param>
		/// <param name="updatedBuildTypeDependency">Indicates the <see cref="BuildType" /> that is executed when the item has changed.</param>
		protected DocProjectItemBase(bool removeOnClean, bool includeInProject, MissingBuildTypeDependency missingBuildTypeDependency, UpdatedBuildTypeDependency updatedBuildTypeDependency, bool isRequiredOutput)
			: this(removeOnClean, includeInProject, missingBuildTypeDependency, updatedBuildTypeDependency)
		{
			this.isRequiredOutput = isRequiredOutput;
		}
		#endregion

		#region Methods
		public abstract bool Delete(IAnyProject project);

		public virtual bool HasChangedSince(DateTime dateTime)
		{
			return Path.HasChangedSince(dateTime);
		}

		public override string ToString()
		{
			return Path;
		}
		#endregion
	}
}
